$NetBSD$

--- src/VBox/HostDrivers/VBoxNetAdp/netbsd/VBoxNetAdp-netbsd.c.orig	2016-07-07 07:08:46.543692306 +0000
+++ src/VBox/HostDrivers/VBoxNetAdp/netbsd/VBoxNetAdp-netbsd.c
@@ -0,0 +1,326 @@
+/*  VBoxNetAdp-netbsd.c $ */
+/** @file
+ * VBoxNetAdp - Virtual Network Adapter Driver (Host), NetBSD Specific Code.
+ */
+
+/*-
+ * Copyright (c) 2009 Fredrik Lindberg <fli@shapeshifter.se>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include <sys/param.h>
+#undef PVM
+#include <sys/types.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/fcntl.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+#include <net/bpf.h>
+
+#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
+#include <VBox/version.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <iprt/initterm.h>
+#include <iprt/string.h>
+#include <iprt/spinlock.h>
+#include <iprt/process.h>
+#include <iprt/assert.h>
+#include <iprt/uuid.h>
+#include <iprt/alloc.h>
+#include <iprt/err.h>
+
+#define VBOXNETADP_OS_SPECFIC 1
+#include "../VBoxNetAdpInternal.h"
+
+# include <sys/jail.h>
+# include <net/vnet.h>
+
+# define VBOXCURVNET_SET(arg)           CURVNET_SET_QUIET(arg)
+# define VBOXCURVNET_SET_FROM_UCRED()   VBOXCURVNET_SET(CRED_TO_VNET(curthread->td_ucred))
+# define VBOXCURVNET_RESTORE()          CURVNET_RESTORE()
+
+static int VBoxNetAdpNetBSDCtrlioctl(struct cdev *, u_long, caddr_t, int flags,
+    struct thread *);
+static struct cdevsw vboxnetadp_cdevsw =
+{
+    .d_version = D_VERSION,
+    .d_ioctl = VBoxNetAdpNetBSDCtrlioctl,
+    .d_read = (d_read_t *)nullop,
+    .d_write = (d_write_t *)nullop,
+    .d_name = VBOXNETADP_CTL_DEV_NAME,
+};
+
+static struct cdev *VBoxNetAdpNetBSDcdev;
+
+static int VBoxNetAdpNetBSDModuleEvent(struct module *, int, void *);
+static moduledata_t g_VBoxNetAdpNetBSDModule = {
+    "vboxnetadp",
+    VBoxNetAdpNetBSDModuleEvent,
+    NULL
+};
+
+/** Declare the module as a pseudo device. */
+DECLARE_MODULE(vboxnetadp, g_VBoxNetAdpNetBSDModule, SI_SUB_PSEUDO, SI_ORDER_ANY);
+MODULE_VERSION(vboxnetadp, 1);
+MODULE_DEPEND(vboxnetadp, vboxdrv, 1, 1, 1);
+MODULE_DEPEND(vboxnetadp, vboxnetflt, 1, 1, 1);
+
+/**
+ * Module event handler
+ */
+static int
+VBoxNetAdpNetBSDModuleEvent(struct module *pMod, int enmEventType, void *pvArg)
+{
+    int rc = 0;
+
+    Log(("VBoxNetAdpNetBSDModuleEvent\n"));
+
+    switch (enmEventType)
+    {
+        case MOD_LOAD:
+            rc = RTR0Init(0);
+            if (RT_FAILURE(rc))
+            {
+                Log(("RTR0Init failed %d\n", rc));
+                return RTErrConvertToErrno(rc);
+            }
+            rc = vboxNetAdpInit();
+            if (RT_FAILURE(rc))
+            {
+                RTR0Term();
+                Log(("vboxNetAdpInit failed %d\n", rc));
+                return RTErrConvertToErrno(rc);
+            }
+            /* Create dev node */
+            VBoxNetAdpNetBSDcdev = make_dev(&vboxnetadp_cdevsw, 0,
+                UID_ROOT, GID_WHEEL, 0600, VBOXNETADP_CTL_DEV_NAME);
+
+            break;
+
+        case MOD_UNLOAD:
+            vboxNetAdpShutdown();
+            destroy_dev(VBoxNetAdpNetBSDcdev);
+            RTR0Term();
+            break;
+        case MOD_SHUTDOWN:
+        case MOD_QUIESCE:
+        default:
+            return EOPNOTSUPP;
+    }
+
+    if (RT_SUCCESS(rc))
+        return 0;
+    return RTErrConvertToErrno(rc);
+}
+
+/**
+ * Device I/O Control entry point.
+ */
+static int
+VBoxNetAdpNetBSDCtrlioctl(struct cdev *dev, u_long iCmd, caddr_t data, int flags, struct thread *td)
+{
+    PVBOXNETADP pAdp;
+    PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)data;
+    struct ifnet *ifp;
+    int rc;
+
+    switch (iCmd)
+    {
+        case VBOXNETADP_CTL_ADD:
+            if (   !(iCmd & IOC_INOUT)   /* paranoia*/
+                || IOCPARM_LEN(iCmd) < sizeof(*pReq))
+                return EINVAL;
+
+            rc = vboxNetAdpCreate(&pAdp,
+                                  pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(IOCPARM_LEN(iCmd), sizeof(pReq->szName))) ?
+                                  pReq->szName : NULL);
+            if (RT_FAILURE(rc))
+                return EINVAL;
+
+            strncpy(pReq->szName, pAdp->szName, sizeof(pReq->szName) - 1);
+            pReq->szName[sizeof(pReq->szName) - 1] = '\0';
+            break;
+
+        case VBOXNETADP_CTL_REMOVE:
+            if (!RTStrEnd(pReq->szName, RT_MIN(sizeof(pReq->szName), IOCPARM_LEN(iCmd))))
+                return EINVAL;
+
+            pAdp = vboxNetAdpFindByName(pReq->szName);
+            if (!pAdp)
+                return EINVAL;
+
+            rc = vboxNetAdpDestroy(pAdp);
+            if (RT_FAILURE(rc))
+                return EINVAL;
+
+            break;
+
+        default:
+            return EINVAL;
+    }
+    return 0;
+}
+
+/**
+ * Initialize device, just set the running flag.
+ */
+static void VBoxNetAdpNetBSDNetinit(void *priv)
+{
+    PVBOXNETADP pThis = priv;
+    struct ifnet *ifp = pThis->u.s.ifp;
+
+    ifp->if_drv_flags |= IFF_DRV_RUNNING;
+}
+
+/**
+ * Transmit packets.
+ * netflt has already done everything for us so we just hand the
+ * packets to BPF and increment the packet stats.
+ */
+static void VBoxNetAdpNetBSDNetstart(struct ifnet *ifp)
+{
+    PVBOXNETADP pThis = ifp->if_softc;
+    struct mbuf *m;
+
+    if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING)
+        return;
+
+    ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+    while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+    {
+        ifp->if_opackets++;
+        IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+        BPF_MTAP(ifp, m);
+        m_freem(m);
+    }
+    ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+}
+
+/**
+ * Interface ioctl handling
+ */
+static int VBoxNetAdpNetBSDNetioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+    int error = 0;
+
+    switch (cmd)
+    {
+        case SIOCSIFFLAGS:
+            if (ifp->if_flags & IFF_UP)
+            {
+                if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+                    ifp->if_init(ifp->if_softc);
+            }
+            else
+            {
+                if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+                    ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+            }
+            break;
+        case SIOCGIFMEDIA:
+        {
+            struct ifmediareq *ifmr;
+            int count;
+
+            ifmr = (struct ifmediareq *)data;
+            count = ifmr->ifm_count;
+            ifmr->ifm_count = 1;
+            ifmr->ifm_status = IFM_AVALID;
+            ifmr->ifm_active = IFM_ETHER;
+            ifmr->ifm_status |= IFM_ACTIVE;
+            ifmr->ifm_current = ifmr->ifm_active;
+            if (count >= 1)
+            {
+                int media = IFM_ETHER;
+                error = copyout(&media, ifmr->ifm_ulist, sizeof(int));
+            }
+            break;
+        }
+        default:
+            return ether_ioctl(ifp, cmd, data);
+    }
+    return error;
+}
+
+int vboxNetAdpOsInit(PVBOXNETADP pThis)
+{
+    pThis->u.s.ifp = NULL;
+    return VINF_SUCCESS;;
+}
+
+int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMac)
+{
+    struct ifnet *ifp;
+
+    VBOXCURVNET_SET_FROM_UCRED();
+    ifp = if_alloc(IFT_ETHER);
+    if (ifp == NULL)
+        return VERR_NO_MEMORY;
+
+    if_initname(ifp, VBOXNETADP_NAME, pThis->iUnit);
+    ifp->if_softc = pThis;
+    ifp->if_mtu = ETHERMTU;
+    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+    ifp->if_ioctl = VBoxNetAdpNetBSDNetioctl;
+    ifp->if_start = VBoxNetAdpNetBSDNetstart;
+    ifp->if_init = VBoxNetAdpNetBSDNetinit;
+    IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+    ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
+    IFQ_SET_READY(&ifp->if_snd);
+    ether_ifattach(ifp, (void *)pMac);
+    ifp->if_baudrate = 0;
+
+    strncpy(pThis->szName, ifp->if_xname, VBOXNETADP_MAX_NAME_LEN);
+    pThis->u.s.ifp = ifp;
+    VBOXCURVNET_RESTORE();
+    return 0;
+}
+
+void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
+{
+    struct ifnet *ifp;
+
+    ifp = pThis->u.s.ifp;
+    VBOXCURVNET_SET(ifp->if_vnet);
+    ether_ifdetach(ifp);
+    if_free(ifp);
+    VBOXCURVNET_RESTORE();
+}
